package com.cyl.wechat;

import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;
import com.github.wxpay.sdk.WXPay;
import com.github.wxpay.sdk.WXPayConstants;
import com.github.wxpay.sdk.WXPayUtil;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
@ConditionalOnProperty(prefix = "wechat", name = "enabled", havingValue = "true")
public class WechatPayService {

    public Map<String, String> appPay(String orderNo, String desc, Integer totalAmount, Long memberId, String appId, String notifyUrl) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("body", desc);
            data.put("out_trade_no", orderNo);
            data.put("total_fee", String.valueOf(totalAmount)); // 单位为分
            data.put("spbill_create_ip", "127.0.0.1");
            data.put("notify_url", notifyUrl != null ? notifyUrl : "https://www.bjshangyu.cn/appApi/no-auth/wechat/notify");
            data.put("trade_type", "APP");
            data.put("attach", String.valueOf(memberId));

            Map<String, String> resp = wxpay.unifiedOrder(data);
            if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
                // V2 需要返回给前端一组参数（签名等），不是直接返回 prepay_id
                Map<String, String> result = new HashMap<>();
                result.put("appid", config.getAppID());
                result.put("partnerid", config.getMchID());
                result.put("prepayid", resp.get("prepay_id"));
                result.put("package", "Sign=WXPay");
                result.put("noncestr", WXPayUtil.generateNonceStr());
                result.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
                // 这里需要对参数进行签名
                String sign = WXPayUtil.generateSignature(result, config.getKey(), WXPayConstants.SignType.MD5);
                result.put("sign", sign);
                // 返回给前端的参数
                return result;
            } else {
                String errorMsg = resp.get("return_msg");
                if (resp.containsKey("err_code_des")) {
                    errorMsg = resp.get("err_code_des");
                }
                throw new RuntimeException("微信支付下单失败：" + errorMsg);
            }
        } catch (Exception e) {
            log.error("微信支付异常", e);
            throw new RuntimeException("微信支付异常: " + e.getMessage(), e);
        }
    }

    public Map<String, String> refundPay(String refundId, String payId, Long refundAmount, Long totalAmount, String reason) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            // 修复构造函数参数
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("out_trade_no", payId);
            data.put("out_refund_no", refundId);
            data.put("total_fee", String.valueOf(totalAmount));
            data.put("refund_fee", String.valueOf(refundAmount));
            data.put("refund_desc", reason);

            Map<String, String> resp = wxpay.refund(data);

            if ("SUCCESS".equals(resp.get("return_code"))) {
                if ("SUCCESS".equals(resp.get("result_code"))) {
                    Map<String, String> result = new HashMap<>();
                    result.put("refund_id", resp.get("refund_id"));
                    result.put("out_refund_no", resp.get("out_refund_no"));
                    result.put("refund_fee", resp.get("refund_fee"));
                    result.put("total_fee", resp.get("total_fee"));
                    result.put("result_code", "SUCCESS");
                    return result;
                } else {
                    String errorMsg = "未知错误";
                    if (resp.containsKey("err_code_des")) {
                        errorMsg = resp.get("err_code_des");
                    } else if (resp.containsKey("err_code")) {
                        errorMsg = resp.get("err_code");
                    }
                    throw new RuntimeException("微信退款失败：" + errorMsg);
                }
            } else {
                String errorMsg = resp.get("return_msg");
                throw new RuntimeException("微信退款通信失败：" + errorMsg);
            }
        } catch (Exception e) {
            log.error("微信退款异常", e);
            throw new RuntimeException("微信退款异常: " + e.getMessage(), e);
        }
    }

    /**
     * 查询退款状态
     */
    public Map<String, String> queryRefund(String refundId, String payId) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("out_trade_no", payId);
            data.put("out_refund_no", refundId);

            Map<String, String> resp = wxpay.refundQuery(data);

            if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
                return resp;
            } else {
                String errorMsg = resp.get("return_msg");
                if (resp.containsKey("err_code_des")) {
                    errorMsg = resp.get("err_code_des");
                }
                throw new RuntimeException("查询退款失败：" + errorMsg);
            }
        } catch (Exception e) {
            log.error("查询退款异常", e);
            throw new RuntimeException("查询退款异常: " + e.getMessage(), e);
        }
    }

    /**
     * 查询订单状态
     */
    public Map<String, String> queryOrder(String orderNo) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("nonce_str", WXPayUtil.generateNonceStr());
            data.put("out_trade_no", orderNo);

            Map<String, String> resp = wxpay.orderQuery(data);

            if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
                return resp;
            } else {
                String errorMsg = resp.get("return_msg");
                if (resp.containsKey("err_code_des")) {
                    errorMsg = resp.get("err_code_des");
                }
                throw new RuntimeException("查询订单失败：" + errorMsg);
            }
        } catch (Exception e) {
            log.error("查询订单异常", e);
            throw new RuntimeException("查询订单异常: " + e.getMessage(), e);
        }
    }

    /**
     * 委托代扣签约
     * @param contractCode 商户侧签约协议号
     * @param planId 协议模板ID
     * @param userDisplayName 用户展示名称
     * @param notifyUrl 签约成功通知URL
     * @param memberId 用户ID
     * @return 签约结果
     */
    public Map<String, Object> contractSign(String contractCode, String planId, String userDisplayName) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("contract_code", contractCode);
            data.put("request_serial", String.valueOf(System.currentTimeMillis()));
            data.put("contract_display_account", userDisplayName);
            data.put("notify_url", "https://www.bjshangyu.cn/appApi/no-auth/wechat/contract/notify");
            data.put("version", "1.0");
            data.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));
            data.put("plan_id", planId);
            data.put("nonce_str", WXPayUtil.generateNonceStr());

            // 生成签名
            String sign = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5);
            data.put("sign", sign);

            // 构造跳转URL
            StringBuilder urlBuilder = new StringBuilder("https://api.mch.weixin.qq.com/papay/entrustweb?");
            for (Map.Entry<String, String> entry : data.entrySet()) {
                urlBuilder.append(entry.getKey()).append("=").append(entry.getValue()).append("&");
            }
            String redirectUrl = urlBuilder.toString();
            if (redirectUrl.endsWith("&")) {
                redirectUrl = redirectUrl.substring(0, redirectUrl.length() - 1);
            }

            Map<String, Object> result = new HashMap<>();
            result.put("redirect_url", redirectUrl);
            result.put("contract_code", contractCode);
            return result;
        } catch (Exception e) {
            log.error("委托代扣签约异常", e);
            throw new RuntimeException("委托代扣签约异常: " + e.getMessage(), e);
        }
    }

    /**
     * 委托代扣申请扣款
     * @param contractId 签约成功后的微信侧签约协议号
     * @param orderNo 商户订单号
     * @param totalAmount 扣款金额（分）
     * @param desc 商品描述
     * @param notifyUrl 扣款结果通知URL
     * @return 扣款结果
     */
    public Map<String, Object> contractPay(String contractId, String orderNo, BigDecimal totalAmount, String desc, String notifyUrl) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("contract_id", contractId);
            data.put("out_trade_no", orderNo);
            // 确保金额转换为分（整数）
            int totalFee = totalAmount.multiply(new BigDecimal("100")).intValue();
            data.put("total_fee", String.valueOf(totalFee));
            data.put("body", desc);
            // 使用真实的客户端IP，而不是127.0.0.1
            data.put("spbill_create_ip", "8.8.8.8"); // 或者从请求中获取真实IP
            data.put("notify_url", notifyUrl != null ? notifyUrl : "https://www.bjshangyu.cn/appApi/no-auth/wechat/contract/pay/notify");
            data.put("trade_type", "PAP");
            data.put("nonce_str", WXPayUtil.generateNonceStr());

            // 生成签名
            String sign = WXPayUtil.generateSignature(data, config.getKey(), WXPayConstants.SignType.MD5);
            data.put("sign", sign);

            // 验证必需参数
            String[] requiredParams = {"appid", "mch_id", "contract_id", "out_trade_no", "total_fee", "body", "spbill_create_ip", "notify_url", "trade_type", "nonce_str", "sign"};
            for (String param : requiredParams) {
                if (!data.containsKey(param) || data.get(param) == null || data.get(param).trim().isEmpty()) {
                    throw new RuntimeException("缺少必需参数: " + param);
                }
            }

            // 添加详细日志输出
            log.info("委托代扣请求参数: {}", data);
            log.info("请求URL: /pay/pappayapply");

            String respXml;
            Map<String, String> resp;
            try {
                respXml = wxpay.requestWithoutCert("/pay/pappayapply", data, 30000, 30000);
                // 解析XML响应为Map
                resp = WXPayUtil.xmlToMap(respXml);
                // 输出响应结果
                log.info("委托代扣响应XML: {}", respXml);
                log.info("委托代扣响应结果: {}", resp);
            } catch (Exception e) {
                log.error("调用requestWithoutCert方法异常: {}", e.getMessage(), e);
                throw new RuntimeException("委托代扣请求异常: " + e.getMessage(), e);
            }

            if ("SUCCESS".equals(resp.get("return_code"))) {
                if ("SUCCESS".equals(resp.get("result_code"))) {
                    Map<String, Object> result = new HashMap<>();
                    result.put("transaction_id", resp.get("transaction_id"));
                    result.put("out_trade_no", resp.get("out_trade_no"));
                    result.put("contract_id", resp.get("contract_id"));
                    result.put("result_code", "SUCCESS");
                    return result;
                } else {
                    String errCode = resp.get("err_code");
                    String errorMsg = resp.get("err_code_des");
                    log.error("委托代扣业务失败 - 错误码: {}, 错误描述: {}", errCode, errorMsg);
                    throw new RuntimeException("委托代扣扣款失败[" + errCode + "]：" + errorMsg);
                }
            } else {
                String returnMsg = resp.get("return_msg");
                log.error("委托代扣通信失败 - 返回信息: {}", returnMsg);
                throw new RuntimeException("委托代扣扣款通信失败：" + returnMsg);
            }
        } catch (Exception e) {
            log.error("委托代扣扣款异常", e);
            throw new RuntimeException("委托代扣扣款异常: " + e.getMessage(), e);
        }
    }

    /**
     * 查询签约关系
     * @param contractId 微信侧签约协议号
     * @return 签约状态
     */
    public Map<String, String> queryContract(String contractId) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("contract_id", contractId);
            data.put("version", "1.0");
            data.put("nonce_str", WXPayUtil.generateNonceStr());

            String respXml = wxpay.requestWithoutCert("/papay/querycontract", data, 30000, 30000);
            Map<String, String> resp = WXPayUtil.xmlToMap(respXml);

            if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
                return resp;
            } else {
                String errorMsg = resp.get("return_msg");
                if (resp.containsKey("err_code_des")) {
                    errorMsg = resp.get("err_code_des");
                }
                throw new RuntimeException("查询签约关系失败：" + errorMsg);
            }
        } catch (Exception e) {
            log.error("查询签约关系异常", e);
            throw new RuntimeException("查询签约关系异常: " + e.getMessage(), e);
        }
    }

    /**
     * 申请解约
     * @param contractId 微信侧签约协议号
     * @param contractTerminateReason 解约原因
     * @return 解约结果
     */
    public Map<String, String> deleteContract(String contractId, String contractTerminateReason) {
        try {
            MyWxPayConfig config = new MyWxPayConfig();
            WXPay wxpay = new WXPay(config);

            Map<String, String> data = new HashMap<>();
            data.put("appid", config.getAppID());
            data.put("mch_id", config.getMchID());
            data.put("contract_id", contractId);
            data.put("contract_termination_remark", contractTerminateReason);
            data.put("version", "1.0");
            data.put("nonce_str", WXPayUtil.generateNonceStr());

            String respXml = wxpay.requestWithoutCert("/papay/deletecontract", data, 30000, 30000);
            Map<String, String> resp = WXPayUtil.xmlToMap(respXml);

            if ("SUCCESS".equals(resp.get("return_code")) && "SUCCESS".equals(resp.get("result_code"))) {
                return resp;
            } else {
                String errorMsg = resp.get("return_msg");
                if (resp.containsKey("err_code_des")) {
                    errorMsg = resp.get("err_code_des");
                }
                throw new RuntimeException("申请解约失败：" + errorMsg);
            }
        } catch (Exception e) {
            log.error("申请解约异常", e);
            throw new RuntimeException("申请解约异常: " + e.getMessage(), e);
        }
    }
}
